#ifndef _YLINKEDLIST_H
#define _YLINKEDLIST_H
#include <tool/ydefine.h>

/** Function pointers struct, use externally */
typedef struct linkedList *linkedList;
/** Data struct, use internally */
typedef struct linkedListData *linkedListData;

/** Struct of linked list function pointers */
struct linkedList {
  /*--- data ---*/
  linkedListData d;
  /*--- function pointers ---*/
  /** Free this linked List from memory.
  <p><b>WARNING:</b> Function will free items in the linked list as well, 
  via the call to <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p>Do NOT free anything taken out of item, 
  e.g. via function pointer call to
  <code>void *(*getItem)(const linkedList)</code>.
  Because the linked list still points to the item. 
  Thus the item in a sense still sits inside the list so
  it's memory will be free by this function.
  </p>
  <p>However you can free the item IF 
  <ul>
  <li>(1) the item's library say so, such as the item's "free" function 
  which is our function pointer <code>boolean (*freeItem)(void **)</code> 
  couldn't and doesn't handle it.
  Thus requiring external program to handle this.
  e.g. Cloned data struct (which it doesn't keep track of).
  </li>
  <li>(2) You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library for details.
  </li>
  </ul>
  </p>
  @param listP pass in the address of linked List struct pointer to be free.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*free)(linkedList *listP);
  /** Returns the number of elements in this list.
  @param list the linked list.
  @return Returns the number of elements in this list or -1 if failure.
  */
  int (*size)(const linkedList list);
  /** Removes all of the elements from this list.
  @param list the linked list.
  @return <code>true</code> if successful 
    otherwise <code>false</code> nothing to remove.
  */
  boolean (*clear)(linkedList list);
  /*--- traverse */
  /** If the list currently point at something.
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*current)(const linkedList list);
  /** Move to next item. Successful if next in list point at something, 
  otherwise stay at the tail of the list.
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*goNext)(linkedList list);
  /** Move back a item. Successful if previous in list point at something, 
  otherwise stay at the head of the list.
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*goBack)(linkedList list);
  /** Move to the first item in the list. 
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*goFirst)(linkedList list);
  /** Move to the last item in the list. 
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*goLast)(linkedList list);
  /** Move to the "mark" item in the list. 
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*goMark)(linkedList list);
  /*--- test */
  /** Tests if this list has no elements.
  @param list the linked list.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*isEmpty)(const linkedList list);
  /** Are we currently pointing to the first item in the list?
  @param list the linked list.
  @return true if pointing to the first item, false otherwise.
  */
  boolean (*isFirst)(const linkedList list);
  /** Are we currently pointing to the last item in the list?
  @param list the linked list.
  @return true if pointing to the last item, false otherwise.
  */
  boolean (*isLast)(const linkedList list);
  /** Is there another item after current item in the list?
  @param list the linked list.
  @return true if successful, false otherwise.
  */
  boolean (*hasNext)(const linkedList list);
  /** Is there another item before current item in the list?
  @param list the linked list.
  @return true if successful, false otherwise.
  */
  boolean (*hasPrevious)(const linkedList list);
  /** Compare a given item against the item currently 
  pointing to within in the list.
  <p>MUST provide the function of the form 
  <code>g_reply (*compareItem)(const void *, const void *)</code>.
  through <code>setFnCompareItem(..)</code> beforehand to 
  able to use this function
  </p>
  <p><code>compareItem</code> should return <code>g_replyEqual</code> 
  if <code>anItem</code> and list's item are equal.
  Returns <code>g_replyLesser</code> or <code>g_replyGreater</code> 
  if <code>anItem</code> is less than or greater than 
  list's item respectively.
  </p>
  <p>This is a customized function provided by the item's library 
  and is NOT compulsory.
  </p>
  @param list the linked list.
  @param anItem the given item to compare 
    against the current item within the list.
  @return Return <code>g_replyEqual</code> 
    if <code>anItem</code> and list's item are equal.
    Returns <code>g_replyLesser</code> or <code>g_replyGreater</code> 
    if <code>anItem</code> is less than or greater than 
    list's item respectively.
    Otherwise <code>g_replyFail</code> for failure.
  */
  g_reply (*compareItem)(const linkedList list, const void *anItem2);
  /*--- item */
  /** Obtain the item of the currently pointing item in the list. 
  <p><b>WARNING:</b> Function will free items in the linked list as well, 
  via the call to <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p>Do NOT free anything taken out of item, 
  e.g. via function pointer call to
  <code>void *(*getItem)(const linkedList)</code>.
  Because the linked list still points to the item. 
  Thus the item in a sense still sits inside the list so
  it's memory will be free by this function.
  </p>
  <p>However you can free the item IF 
  <ul>
  <li>(1) the item's library say so, such as the item's "free" function 
  which is our function pointer <code>boolean (*freeItem)(void **)</code> 
  couldn't and doesn't handle it.
  Thus requiring external program to handle this.
  e.g. Cloned data struct (which it doesn't keep track of).
  </li>
  <li>(2) You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library details.
  </li>
  </ul>
  </p>
  @param list the linked list.
  @return the currently pointing item in the list.
  */
  void *(*getItem)(const linkedList list);
  /** Obtain a "cloned" copy of the item currently pointing to in the list. 
  <p>This is a customized function provided by the item's library 
  and is NOT compulsory.
  </p>
  <p>The customized function is given to the list via function pointer
  <code>boolean (*setFnItemClone)(linkedList, 
      void *(*itemClone)(const void *, const void *))</code>.
  </p>
  <p>You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library for details.
  </p>
  @param list the linked list.
  @param aControlObj an object that customized function may work with,
    e.g. provide cloning ability, other facility and perform other duty.
  @return a "cloned" copy of the item currently pointing to in the list, or
    <code>NULL</code> if failure.
  */
  void *(*getItemClone)(const linkedList list, const void *aControlObj);
  /** Add this item before the current one in the list.
  Allow item to be <code>NULL</code>.
  <p><b>WARNING:</b> once the item is added into this linked list.
  The linked list will handle freeing the item's memory, 
  via call to function pointer <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p><b>NEVER release memory of the item, once you've added into the list, 
  UNLESS your copy is a clone of the one inside the list.</b> 
  You have to handle freeing memory of the clone.
  The list will handle freeing the item it is pointing to.
  </p>
  <p>The 2 possibility of item memory will be release by the linked list are 
  when (1) the item is deleted via call to function pointer
  <code>boolean (*deleteItem)(linkedList)</code>,
  or (2) freeing linked list memory via call to function pointer
  <code>boolean (*free)(linkedList *)</code>.
  </p>
  @param list the linked list.
  @param anItem the item to be added.
  @return true if successfully added the item, false otherwise.
  */
  boolean (*addItemBefore)(linkedList list, void *anItem);
  /** Add this item after the current one in the list.
  Allow item to be <code>NULL</code>.
  <p><b>WARNING:</b> once the item is added into this linked list.
  The linked list will handle freeing the item's memory, 
  via call to function pointer <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p><b>NEVER release memory of the item, once you've added into the list, 
  UNLESS your copy is a clone of the one inside the list.</b> 
  You have to handle freeing memory of the clone.
  The list will handle freeing the item it is pointing to.
  </p>
  <p>The 2 possibility of item memory will be release by the linked list are 
  when (1) the item is deleted via call to function pointer
  <code>boolean (*deleteItem)(linkedList)</code>,
  or (2) freeing linked list memory via call to function pointer
  <code>boolean (*free)(linkedList *)</code>.
  </p>
  @param list the linked list.
  @param anItem the item to be added.
  @return true if successfully added the item, false otherwise.
  */
  boolean (*addItemAfter)(linkedList list, void *anItem);
  /** Delete the current item from the list. 
  After deletion the new current item will become the next item if it exist, 
  otherwise the new current item will become the item in front if it exist.
  If no item exist in front or to the back, the list is empty, 
  current has no item and points to <code>NULL</code>.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*deleteItem)(linkedList list);
  /** Delete the current item from the list 
  BUT will NOT free the deleted item from memory!
  After deletion the new current item will become the next item if it exist, 
  otherwise the new current item will become the item in front if it exist.
  If no item exist in front or to the back, the list is empty, 
  current has no item and points to <code>NULL</code>.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*deleteItemNOTFree)(linkedList list);
  /** Set a new item over the current item in the list, 
  BUT will NOT free the previous item from memory!
  Note this is NOT adding.
  @param list the linked list.
  @param anItem the item to be added.
  @return <code>true</code> if successfully, 
    or <code>false</code> if failure occurs.
  */
  boolean (*setItemNOTFree)(linkedList list, 
      void *anItem);
  /*--- marked item for action */
  /** Mark the current item as "mark" in the list.
  Allow action such as get, move, add & delete 
  to be taken relative to this "mark" item.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*mark)(linkedList list);
  /** Clear the "mark", so that "mark" will point to nothing.
  Previous "mark" item is NOT affected.
  Action afterwards such as get, move, add & delete 
  relative to this cleared "mark" will NOT be successful.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*clearMark)(linkedList list);
  /** Obtain the item of at the marked position in the list. 
  <p><b>WARNING:</b> Function will free items in the linked list as well, 
  via the call to <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p>Do NOT free anything taken out of item, 
  e.g. via function pointer call to
  <code>void *(*getItem)(const linkedList)</code>.
  Because the linked list still points to the item. 
  Thus the item in a sense still sits inside the list so
  it's memory will be free by this function.
  </p>
  <p>However you can free the item IF 
  <ul>
  <li>(1) the item's library say so, such as the item's "free" function 
  which is our function pointer <code>boolean (*freeItem)(void **)</code> 
  couldn't and doesn't handle it.
  Thus requiring external program to handle this.
  e.g. Cloned data struct (which it doesn't keep track of).
  </li>
  <li>(2) You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library details.
  </li>
  </ul>
  </p>
  @param list the linked list.
  @return the item at the marked position in the list.
  */
  void *(*getItemMark)(const linkedList list);
  /** Obtain a "cloned" copy of the item at the marked position in the list. 
  <p>This is a customized function provided by the item's library 
  and is NOT compulsory.
  </p>
  <p>The customized function is given to the list via function pointer
  <code>boolean (*setFnItemClone)(linkedList, 
      void *(*itemClone)(const void *, const void *))</code>.
  </p>
  <p>You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library for details.
  </p>
  @param list the linked list.
  @param aControlObj an object that customized function may work with,
    e.g. provide cloning ability, other facility and perform other duty.
  @return a "cloned" copy of the item at the marked position to in the list, or
    <code>NULL</code> if failure.
  */
  void *(*getItemMarkClone)(const linkedList list, 
      const void *aControlObj);
  /** Add this item before the marked position in the list.
  Allow item to be <code>NULL</code>.
  <p><b>WARNING:</b> once the item is added into this linked list.
  The linked list will handle freeing the item's memory, 
  via call to function pointer <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p><b>NEVER release memory of the item, once you've added into the list, 
  UNLESS your copy is a clone of the one inside the list.</b> 
  You have to handle freeing memory of the clone.
  The list will handle freeing the item it is pointing to.
  </p>
  <p>The 2 possibility of item memory will be release by the linked list are 
  when (1) the item is deleted via call to function pointer
  <code>boolean (*deleteItem)(linkedList)</code>,
  or (2) freeing linked list memory via call to function pointer
  <code>boolean (*free)(linkedList *)</code>.
  </p>
  @param list the linked list.
  @param anItem the item to be added.
  @return true if successfully added the item, false otherwise.
  */
  boolean (*addItemBeforeMark)(linkedList list, void *anItem);
  /** Add this item after the marked position in the list.
  Allow item to be <code>NULL</code>.
  <p><b>WARNING:</b> once the item is added into this linked list.
  The linked list will handle freeing the item's memory, 
  via call to function pointer <code>boolean (*freeItem)(void **)</code>.
  </p>
  <p><b>NEVER release memory of the item, once you've added into the list, 
  UNLESS your copy is a clone of the one inside the list.</b> 
  You have to handle freeing memory of the clone.
  The list will handle freeing the item it is pointing to.
  </p>
  <p>The 2 possibility of item memory will be release by the linked list are 
  when (1) the item is deleted via call to function pointer
  <code>boolean (*deleteItem)(linkedList)</code>,
  or (2) freeing linked list memory via call to function pointer
  <code>boolean (*free)(linkedList *)</code>.
  </p>
  @param list the linked list.
  @param anItem the item to be added.
  @return true if successfully added the item, false otherwise.
  */
  boolean (*addItemAfterMark)(linkedList list, void *anItem);
  /** Delete the item at the marked position from the list. 
  If marked position is the same as currently pointing item 
  and a successful delete has occurred, 
  the new currently pointing item will move accordingly.
  The marked position will be cleared after a successful delete.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*deleteItemMark)(linkedList list);
  /** Move the current item before the "mark" item.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*moveCurItemBeforeMark)(linkedList list);
  /** Move the current item after the "mark" item.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*moveCurItemAfterMark)(linkedList list);
  /** Move the "mark" item before the current item.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*moveMarkBeforeCurItem)(linkedList list);
  /** Move the "mark" item after the current item.
  @param list the linked list.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*moveMarkAfterCurItem)(linkedList list);
  /*--- provide customized function */
  /** Provide a function to clone an item of type <code>void *</code>.
  The function is of the form 
  <code>void *(*itemClone)(const void *, const void *)</code>.
  <p>This is a customized function provided by the item's library 
  and is NOT compulsory.
  </p>
  <p>You SHOULD free this "cloned" copy of the item cloned from the list.
  The list does NOT keep track of these "clones" and shouldn't release them..
  <br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
  AND also release them via the same function pointer call to 
  <code>boolean (*freeItem)(void **)</code>.
  <br/><b>Advice:</b> Read the item's library for details.
  </p>
  @param list the linked list.
  @param itemClone the function to clone an item of type <code>void *</code>.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*setFnItemClone)(linkedList list, 
      void *(*itemClone)(const void *anItem, const void *aControlObj));
  /** Provide a function to compare two items of type <code>void *</code>.
  The function is of the form 
  <code>g_reply (*compareItem)(const void *, const void *)</code>.
  <p>This function will be used for comparing a given item against 
  the item currently pointing to within in the list.
  <br/><code>anItem1</code> is the given item.
  <br/><code>anItem2</code> is the current item within the list.
  </p>
  <p><code>compareItem</code> should return <code>g_replyEqual</code> 
  if <code>anItem1</code> and <code>anItem2</code> are equal.
  Returns <code>g_replyLesser</code> or <code>g_replyGreater</code> 
  if <code>anItem1</code> is less than or greater than 
  <code>anItem2</code> respectively.
  </p>
  <p>This is a customized function provided by the item's library 
  and is NOT compulsory.
  </p>
  @param list the linked list.
  @param compareItem the function to compare 
    two items of type <code>void *</code>.
  @return <code>true</code> if successful otherwise <code>false</code>.
  */
  boolean (*setFnCompareItem)(linkedList list, 
      g_reply (*compareItem)(const void *anItem1, const void *anItem2));
};

/** Create a new linkedList.
<p>MUST provide a function to free an item of type <code>void *</code>.
The function is of the form <code>boolean (*freeItem)(void **)</code>.
</p>
@param freeItem the function to free an item of type <code>void *</code>.
@return a newly created and empty linkedList, 
  or <code>NULL</code> if failure.
*/
linkedList ylinkedList_create(boolean (*freeItem)(void **anItemP));
/** Create a new linkedList with this item.
<p>MUST provide a function to free an item of type <code>void *</code>.
The function is of the form <code>boolean (*freeItem)(void **)</code>.
</p>
@param anItem the item to be added.
@param freeItem the function to free an item of type <code>void *</code>.
@return a newly created linkedList with item, 
  or <code>NULL</code> if failure.
*/
linkedList ylinkedList_createWithItem(void *anItem, 
    boolean (*freeItem)(void **anItemP));

#endif /* _YLINKEDLIST_H */
